/**
 * Company : Thai Informatic System Co., Ltd.
 * Created By : Dr.Tree
 * Created On : Oct 10, 2012  4:22:48 PM 
 * e-Mail : chatree@tis.co.th
 * Mobile Phone : (+66) 087-921-5115
 * Package Name : apps.business.process.construction.contract
 * File Name : ContractConstrutionThreadPoolTest.java
 * TODO
 */
package apps.business.process.construction.contract;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import jpa.entitys.promis.common.CostProject;
import org.apache.log4j.Logger;
import promis.utility.CommonService;
import apps.promis.in.common.ProjectAction;
import apps.promis.out.construction.VwSyncPoContractorAction;

/**
 * @author chatree
 *
 */
public class ContractConstrutionThreadPoolTest {

	private static final Logger log = Logger.getLogger(ContractConstrutionThreadPoolTest.class);
	
	public static void main(String[] args) throws Exception {

		List<CostProject> lst1 = new ProjectAction().findAll();
		log.info("CostProject Size:"+ CommonService.getSize(lst1));
		
		System.out.println("CostProject Size:"+ CommonService.getSize(lst1));
		System.out.print("Please any key : "); System.in.read();
				
		for(CostProject project : lst1){
			int totalRow = -1;
	    	List<Object[]> lst = null;
	    	try{
	    		lst = new VwSyncPoContractorAction().findAllByProject(project.getId().getCompany(), project.getId().getProject(), "N");
	    		log.info("totalRow = " + CommonService.getSize(lst));
	    		if(lst != null){
	    			totalRow = lst.size();		    			
	    		}  		    		
	    	}catch(Exception e)
	    	{
	    		log.error(e.getMessage());
				System.err.println(e.getMessage());
	    	}
	    	
	    	/////////////////////////////////////////////////////////////////////////
		    int numTasks = totalRow;	    
		    int numThreads = 30;
		    
		    log.info("numTasks =" + numTasks + " || numThreads =" + numThreads);
		    
		    System.out.println("numTasks =" + numTasks + " || numThreads =" + numThreads);			    
		    System.out.print("Please any key ="); System.in.read();
		    
		    // create the thread pool
		    ThreadPool threadPool = new ThreadPool(numThreads);

		    // run example tasks
		    for (int i = 0; i < numTasks; i++) {
		    	
		    	Object[] value = lst.get(i);
				String documentNo = CommonService.IsNullRNull(value[2]);
				String status = CommonService.IsNullRNull(value[3]);
				String syncIsstaging = CommonService.IsNullRNull(value[4]);
				String issync = "N";
				
				threadPool.runTask(createTask(project.getId().getCompany(), project.getId().getProject(), documentNo, status, syncIsstaging, issync, i) );   
			}
		    
		    // close the pool and wait for all tasks to finish.
			   threadPool.join();
		  }	
	}

	  /**
	   * Creates a simple Runnable that prints an ID, waits 500 milliseconds, then
	   * prints the ID again.
	   */
	  private static Runnable createTask(final String company, final String project, final String documentNo, final String status, final String syncIsstaging, final String issync, final int taskID) {
	    return new Runnable() {
	      public void run() {
	        System.out.println("Task " + taskID + " , company "+ company+ " , project "+ project+ " , BookingOrContarctNo "+ documentNo+ " , status "+ status+ "  , syncIsstaging "+ syncIsstaging+ " , issync "+ issync+ " : start" + (new Date()));
	        log.info("Task " + taskID + " || company "+ company+ " || project "+ project+ " || BookingOrContarctNo "+ documentNo+ " || status "+ status+ " || syncIsstaging "+ syncIsstaging+ " || issync "+ issync+ " || start" + (new Date()));

	        // simulate a long-running task
	        ////////////////////////////////////////////////////////////////////////////////////////
	        
	        try {
				
	        	new ContractContractorLowRiseProcessing().ProcessingContarct(company, project, documentNo, status, syncIsstaging);
				
			} catch (Exception e) {
				log.error(e.getMessage());
				System.err.println(e.getMessage());
			}
	        
	        
	        //////////////////////////////////////////////////////////////////////////////////////
	        try {
	          Thread.sleep(500);
	        } catch (InterruptedException ex) {
	        	log.error(ex);
	        	ex.getStackTrace();
	        }

	        log.info("Task " + taskID + " || company "+ company+ " || project "+ project+ " || BookingOrContarctNo "+ documentNo+ " || status "+ status+ " || syncIsstaging "+ syncIsstaging+ " || issync "+ issync+ " || End" + (new Date()));
	        System.out.println("Task " + taskID + " , company "+ company + " , project "+ project+ " , documentNo "+ documentNo+ " , status "+ status+ "  , syncIsstaging "+ syncIsstaging+ " , issync "+ issync+ " : end"  + (new Date()));
	      }
	    };
	  }

	}
	/**
	 * A thread pool is a group of a limited number of threads that are used to
	 * execute tasks.
	 */

	class ThreadPool extends ThreadGroup {

	  private boolean isAlive;

	  private LinkedList taskQueue;

	  private int threadID;

	  private static int threadPoolID;

	  /**
	   * Creates a new ThreadPool.
	   * 
	   * @param numThreads
	   *            The number of threads in the pool.
	   */
	  public ThreadPool(int numThreads) {
	    super("ThreadPool-" + (threadPoolID++));
	    setDaemon(true);

	    isAlive = true;

	    taskQueue = new LinkedList();
	    for (int i = 0; i < numThreads; i++) {
	      new PooledThread().start();
	    }
	  }

	  /**
	   * Requests a new task to run. This method returns immediately, and the task
	   * executes on the next available idle thread in this ThreadPool.
	   * <p>
	   * Tasks start execution in the order they are received.
	   * 
	   * @param task
	   *            The task to run. If null, no action is taken.
	   * @throws IllegalStateException
	   *             if this ThreadPool is already closed.
	   */
	  public synchronized void runTask(Runnable task) {
	    if (!isAlive) {
	      throw new IllegalStateException();
	    }
	    if (task != null) {
	      taskQueue.add(task);
	      notify();
	    }

	  }

	  protected synchronized Runnable getTask() throws InterruptedException {
	    while (taskQueue.size() == 0) {
	      if (!isAlive) {
	        return null;
	      }
	      wait();
	    }
	    return (Runnable) taskQueue.removeFirst();
	  }

	  /**
	   * Closes this ThreadPool and returns immediately. All threads are stopped,
	   * and any waiting tasks are not executed. Once a ThreadPool is closed, no
	   * more tasks can be run on this ThreadPool.
	   */
	  public synchronized void close() {
	    if (isAlive) {
	      isAlive = false;
	      taskQueue.clear();
	      interrupt();
	    }
	  }

	  /**
	   * Closes this ThreadPool and waits for all running threads to finish. Any
	   * waiting tasks are executed.
	   */
	  public void join() {
	    // notify all waiting threads that this ThreadPool is no
	    // longer alive
	    synchronized (this) {
	      isAlive = false;
	      notifyAll();
	    }

	    // wait for all threads to finish
	    Thread[] threads = new Thread[activeCount()];
	    int count = enumerate(threads);
	    for (int i = 0; i < count; i++) {
	      try {
	        threads[i].join();
	      } catch (InterruptedException ex) {
	      }
	    }
	  }

	  /**
	   * A PooledThread is a Thread in a ThreadPool group, designed to run tasks
	   * (Runnables).
	   */
	  private class PooledThread extends Thread {

	    public PooledThread() {
	      super(ThreadPool.this, "PooledThread-" + (threadID++));
	    }

	    public void run() {
	      while (!isInterrupted()) {

	        // get a task to run
	        Runnable task = null;
	        try {
	          task = getTask();
	        } catch (InterruptedException ex) {
	        }

	        // if getTask() returned null or was interrupted,
	        // close this thread by returning.
	        if (task == null) {
	          return;
	        }

	        // run the task, and eat any exceptions it throws
	        try {
	          task.run();
	        } catch (Throwable t) {
	          uncaughtException(this, t);
	        }
	      }
	    }
	  }

}
